from django.views.generic import ListView,View
from django.shortcuts import render,redirect,get_object_or_404,HttpResponseRedirect
from django.contrib import messages  # 用于添加操作提示信息
from base import models as baseModels
from store import  models as storeModels
from django.db.models import F,Q,Max,Value, CharField
from django.db import transaction
from django import forms
from django.core.files import File
from django.forms.models import model_to_dict
from django.utils import timezone
from django.conf import settings
import ast,datetime
import json,os,shutil
from django.contrib.auth.mixins import LoginRequiredMixin
# Create your views here.
class StoresView(LoginRequiredMixin,ListView):
    """
    HomeView for website views.
    ListView 参数
    model 指定模型类（如 model = Book），自动查询该模型的所有数据
    queryset 自定义查询集（如 queryset = Book.objects.filter(price__gt=50)），优先级高于 model
    ordering 指定默认排序方式（如 ordering = ['-publish_date'] 或 ordering = '-price'）
    paginate_by 分页大小（如 paginate_by = 10 表示每页显示 10 条）
    paginate_orphans 最后一页允许的最小剩余条数（如 paginate_orphans = 3，避免最后一页只有 1-2 条数据）
    allow_empty 是否允许空列表（默认 True，空列表时正常显示；设为 False 会返回 404）
    template_name 自定义模板路径（如 template_name = 'myapp/book_list.html'）
    template_name_suffix 模板名后缀（默认 _list，结合模型名自动生成模板名，如 book_list.html）
    context_object_name 模板中使用的列表变量名（默认是模型名小写加 _list，如 book_list；可自定义为 books）
    get_context_data()	 重写该方法添加额外上下文（如传递分类、统计数据等）
    def get_context_data(self, **kwargs):
        context = super().get_context_data(** kwargs)
        context['category'] = "小说"  # 额外传递分类信息
        context['total_count'] = self.get_queryset().count()  # 总条数
        return context
    page_kwarg 分页参数名（默认 page，如 URL 中的 ?page=2；可改为 p 即 ?p=2）
    paginator_class 自定义分页器类（默认 django.core.paginator.Paginator）
    http_method_names 允许的 HTTP 方法（默认 ['get', 'head', 'options']，通常无需修改）
    extra_context 静态额外上下文（字典形式，如 extra_context = {'title': '书籍列表'}）

    """

    @classmethod
    def get_detail_data(cls, request):
        detail_data = []

        search_q = request.POST.get('q', '').strip()
        # 状态筛选（select_type）：默认 None（不过滤）
        select_type = request.POST.get('select_type')  # 启用，停用

        material_type = request.POST.get('material_type_search', 'all')
        if select_type == '0':  # 根据订单显示
            # 物料类型与模型的映射关系（替代冗长的if-elif）
            MODEL_MAP = {
                'raw': storeModels.StoreRawOrderModel,
                'additive': storeModels.StoreAdditiveOrderModel,
                'packaging': storeModels.StorePackagingOrderModel,
                'intermediate': storeModels.StoreIntermediateOrderModel,
                'finished': storeModels.StoreFinishedOrderModel,

            }
        else:
            MODEL_MAP = {
                'raw': storeModels.StoreRawDetailModel,
                'additive': storeModels.StoreAdditiveDetailModel,
                'packaging': storeModels.StorePackagingDetailModel,
                'intermediate': storeModels.StoreIntermediateDetailModel,
                'finished': storeModels.StoreFinishedDetailModel,

            }
        queryset=[]
        if select_type == '0':  # 根据订单显示
            if material_type == 'all':
                raw_query = MODEL_MAP.get('raw').objects.annotate(
                    wl=Value('raw', output_field=CharField())
                ).filter(orderId__icontains=search_q, ).all()
                additive_query = MODEL_MAP.get('additive').objects.annotate(
                    wl=Value('additive', output_field=CharField())
                ).filter(orderId__icontains=search_q, ).all()
                packaging_query = MODEL_MAP.get('packaging').objects.annotate(
                    wl=Value('packaging', output_field=CharField())
                ).filter(orderId__icontains=search_q, ).all()
                intermediate_query = MODEL_MAP.get('intermediate').objects.annotate(
                    wl=Value('intermediate', output_field=CharField())
                ).filter(orderId__icontains=search_q, ).all()
                finished_query = MODEL_MAP.get('finished').objects.annotate(
                    wl=Value('finished', output_field=CharField())
                ).filter(orderId__icontains=search_q, ).all()
                # 3. 根据参数过滤查询集
                # 注意：union 后的查询集是 "联合查询集"，需先转为列表再过滤，或使用 Q 对象（视模型字段兼容性而定）

                # 重新合并过滤后的查询集
                queryset = raw_query.union(additive_query, all=True).union(packaging_query, all=True
                                                                           ).union(intermediate_query, all=True).union(
                    finished_query, all=True)
            else:
                queryset = MODEL_MAP.get(material_type).objects.annotate(
                    wl=Value(material_type, output_field=CharField())
                ).filter(orderId__icontains=search_q, )
        else:
            if material_type == 'all':
                raw_query = MODEL_MAP.get('raw').objects.annotate(
                    wl=Value('raw', output_field=CharField())
                ).filter(raw__name__icontains=search_q,).all()
                additive_query = MODEL_MAP.get('additive').objects.annotate(
                    wl=Value('additive', output_field=CharField())
                ).filter(raw__name__icontains=search_q,).all()
                packaging_query = MODEL_MAP.get('packaging').objects.annotate(
                    wl=Value('packaging', output_field=CharField())
                ).filter(raw__name__icontains=search_q,).all()
                intermediate_query = MODEL_MAP.get('intermediate').objects.annotate(
                    wl=Value('intermediate', output_field=CharField())
                ).filter(raw__name__icontains=search_q,).all()
                finished_query = MODEL_MAP.get('finished').objects.annotate(
                    wl=Value('finished', output_field=CharField())
                ).filter(raw__name__icontains=search_q,).all()
                # 3. 根据参数过滤查询集
                # 注意：union 后的查询集是 "联合查询集"，需先转为列表再过滤，或使用 Q 对象（视模型字段兼容性而定）

                # 重新合并过滤后的查询集
                queryset = raw_query.union(additive_query, all=True).union(packaging_query, all=True
                        ).union(intermediate_query, all=True).union(finished_query, all=True )
            else:
                queryset = MODEL_MAP.get(material_type).objects.annotate(
                    wl=Value(material_type, output_field=CharField())
                ).filter(raw__name__icontains=search_q,)

        # 4. 最终排序（必须在过滤后执行，否则可能失效）
        # # 获取数据并转换为字典
        items = queryset.order_by('-create_at').all()
        for item in items:
            item_dict = model_to_dict(item)
            # 关键：添加注解的 wl 字段（item.wl 是 annotate 生成的值）
            item_dict['wl'] = item.wl  # 新增这一行

            # 处理日期时间类型（转换为字符串）
            for key, value in item_dict.items():
                if isinstance(value, timezone.datetime):
                    item_dict[key] = value.strftime('%Y-%m-%d %H:%M:%S')
                elif isinstance(value, datetime.date):
                    item_dict[key] = value.strftime('%Y-%m-%d')
            detail_data.append(item_dict)
        return detail_data

    # model = baseModels.RawModel
    # ordering = ['id']  # 必加：指定默认排序（避免 Django 警告，也能解决部分元数据初始化问题）
    context_object_name = 'wl_list'  # 可选：自定义模板变量名
    paginate_by =8  # 可选：分页
    template_name='store/storemodel_list.html'
    def get_queryset(self):
        # 2. 获取前端提交的搜索参数（从 self.request.GET 中提取）
        # 搜索关键词（q）：默认空字符串
        search_q = self.request.GET.get('q', '').strip()
        # 状态筛选（select_type）：默认 None（不过滤） 根据品种显示
        select_type = self.request.GET.get('select_type','1')
        material_type = self.request.GET.get('material_type_search','all')

        # 物料类型与模型的映射关系（替代冗长的if-elif）
        MODEL_MAP = {
            'raw': storeModels.StoreRawDetailModel,
            'additive': storeModels.StoreAdditiveDetailModel,
            'packaging': storeModels.StorePackagingDetailModel,
            'intermediate': storeModels.StoreIntermediateDetailModel,
            'finished': storeModels.StoreFinishedDetailModel,


        }
        if select_type=='0': #根据订单显示
            MODEL_MAP = {
                'raw': storeModels.StoreRawOrderModel,
                'additive': storeModels.StoreAdditiveOrderModel,
                'packaging': storeModels.StorePackagingOrderModel,
                'intermediate': storeModels.StoreIntermediateOrderModel,
                'finished': storeModels.StoreFinishedOrderModel,


            }
        # 1. 定义查询公共逻辑（避免重复代码）
        def get_model_query(model, material_type, search_q, select_type):
            if select_type == '1':
                q=model.objects.annotate(
                    wl=Value(material_type, output_field=CharField())  # 注解为当前物料类型
                ).filter(
                    raw__name__icontains=search_q,

                ).all()
            if select_type=='0': #根据订单显示

                q = model.objects.annotate(
                    wl=Value(material_type, output_field=CharField())  # 注解为当前物料类型
                ).filter(
                    orderId__icontains=search_q,

                ).all()
            return q

        # 3. 分情况查询并合并结果
        queryset = []
        if material_type == 'all':
            # 合并所有模型的查询结果（Python 列表合并，保留原始模型）
            for m_type, model in MODEL_MAP.items():
                queryset.extend(get_model_query(model, m_type, search_q, select_type))
        else:
            # 只查询指定模型
            model = MODEL_MAP.get(material_type)
            if model:
                queryset.extend(get_model_query(model, material_type, search_q, select_type))

        # 后续可对 queryset 进行排序、切片等操作（注意：此时是列表，需用 Python 方法）

        # 示例：按名称排序
        queryset.sort(key=lambda x: x.create_at,reverse=True)

        # 4. 最终排序（必须在过滤后执行，否则可能失效）
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # 额外传递分类信息
        code = 'store.StoreModel'
        context['reports'] = baseModels.ReportFileModel.objects.filter(code=code, type='1', state='1').order_by('-default').all()
        context['report_code'] = code
        context['report_type'] = '1'
        context['total_count'] = len(self.get_queryset())  # 总条数
        return context

class StoreForm(forms.Form):
    STATE_CHOICES = [
        ("1", "启用"),
        ("0", "停用"),
    ]
    TYPE_CHOICES = [
        ("1", "入库单"),
        ("0", "期初入库单"),
    ]
    INVOICE_CHOICES = [
        ("1", "没有发票"),
        ("0", "有发票"),
    ]
    # 基础字段（保持原有逻辑，优化默认值和提示）
    orderId = forms.CharField(
        max_length=50,
        label='品名',
        initial='',
        widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入订单号或自动生成'})
    )
    date = forms.DateField(
        label='日期',
        initial=timezone.now().date(),  # 修正：默认值取日期（不含时间），避免前端格式问题
        widget=forms.DateInput(
            attrs={'class': 'form-control', 'type': 'date'},  # 用原生日期选择器，更友好
            format='%Y-%m-%d'  # 日期格式统一
        ),
        input_formats=['%Y-%m-%d']  # 允许的输入格式
    )
    type = forms.ChoiceField(
        label='状态',
        initial='1',
        choices=TYPE_CHOICES,
        widget=forms.Select(attrs={'class': 'form-select'})
    )
    invoice = forms.ChoiceField(
        label='状态',
        initial='1',
        choices=INVOICE_CHOICES,
        widget=forms.Select(attrs={'class': 'form-select'})
    )


    state = forms.ChoiceField(
        label='状态',
        initial='1',
        choices=STATE_CHOICES,
        widget=forms.Select(attrs={'class': 'form-select'})
    )


    remark = forms.CharField(
        max_length=255,
        label='备注',
        initial='',
        required=False,
        widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': '可选，输入备注信息'})
    )

    # 物料类型单选框（新增禁用"包材"的逻辑）
    MATERIAL_TYPE_CHOICES = [
        ("raw", "原料"),
        ("additive", "添加剂"),
        ("packaging", "包材"),  # 需要禁用的选项
        ("intermediate", "中间品"),  # 需要禁用的选项
        ("finished", "成品"),  # 需要禁用的选项
    ]
    material_type = forms.ChoiceField(
        label="供应物料类型",
        choices=MATERIAL_TYPE_CHOICES,
        widget=forms.RadioSelect(
            attrs={
                'class': 'form-check-input d-flex gap-4 align-items-center form-check-inline',  # 横向布局核心类
                # 补充：每个选项的父容器样式（通过 widget 的 template_name 或直接加类）
            }
        ),
        required=True
    )
    supplier = forms.ChoiceField(
        label="供应商",
        choices=MATERIAL_TYPE_CHOICES,
        widget=forms.Select(
            attrs={
                'class': 'form-check-input d-flex gap-4 align-items-center form-check-inline',  # 横向布局核心类
                # 补充：每个选项的父容器样式（通过 widget 的 template_name 或直接加类）
            }
        ),
        required=True
    )
    # 修正：Form 中用 MultipleChoiceField 替代 ManyToManyField（关联原料选择）
    # raws = forms.MultipleChoiceField(
    #     label="关联原料",
    #     required=False,  # 根据需求调整是否必填
    #     widget=forms.SelectMultiple(attrs={'class':'form-select'}),
    #     # choices=[(1,'a'),(2,'cafasfsaf')],  # 初始为空，在 __init__ 中动态加载原料数据
    #     # initial=[1,]
    # )
    # 修正：Form 中用 MultipleChoiceField 替代 ManyToManyField（关联原料选择）


class StoreView(LoginRequiredMixin,View):
    """物料添加视图：处理原料、添加剂、包装材料的添加逻辑"""
    template_name = 'store/store.html'  # 模板路径集中管理
    success_url = 'store_list'  # 成功后重定向的URL名称（需在urls.py中定义）

    # 物料类型与模型的映射关系（替代冗长的if-elif）
    MODEL_MAP = {
        'raw': storeModels.StoreRawOrderModel,
        'additive': storeModels.StoreAdditiveOrderModel,
        'packaging': storeModels.StorePackagingOrderModel,
        'intermediate': storeModels.StoreIntermediateOrderModel,
        'finished': storeModels.StoreFinishedOrderModel,

    }


    def get(self, request):
        """展示空表单"""
        material_raws_map=[]
        pk=request.GET.get('pk')
        material_type=request.GET.get('material_type')  # 从URL获取模型类型（raw/additive/packaging）
        select_type = request.GET.get('select_type',1) #0为订单

        if pk and material_type:
            # 编辑场景：1. 获取对应模型类 2. 查询实例 3. 提取字段值作为initial
            model_class = self.MODEL_MAP.get(material_type)
            if not model_class:
                messages.error(request, "无效的物料类型")
                return redirect(self.success_url)
            if select_type=='0':
                # 获取模型实例（不存在返回404）
                instance = get_object_or_404(model_class, pk=pk)
            else:
                # 物料类型与模型的映射关系（替代冗长的if-elif）
                MODEL_MAP = {
                    'raw': storeModels.StoreRawDetailModel,
                    'additive': storeModels.StoreAdditiveDetailModel,
                    'packaging': storeModels.StorePackagingDetailModel,
                    'intermediate': storeModels.StoreIntermediateDetailModel,
                    'finished': storeModels.StoreFinishedDetailModel,

                }
                detail=MODEL_MAP.get(material_type).objects.filter(pk=pk).first()

                instance = detail.store_order

            # 构造initial数据：表单字段名与模型字段名必须一致
            initial_data = {
                'orderId': instance.orderId,
                'date': instance.date,
                'type': instance.type,
                'invoice': instance.invoice,
                'supplier': instance.supplier if instance.supplier else '生产车间',
                'remark': instance.remark,
                'material_type': material_type,  # 回显物料类型单选框
                # 'raws': instance.raws,  # 多选项回显：传递ID列表
            }

            # # 传入initial数据，表单自动回显
            form = StoreForm(initial=initial_data)

        else:
            # 新增场景：空表单（若URL带model_type，可默认选中该类型）
            instance = {'material_type': material_type} if material_type else {}
            form = StoreForm(initial=instance)
            # material_raws_map = {'raw':[[item.id,item.name] for item in baseModels.RawModel.objects.filter(state='1').all()],
            #                      'additive':[[item.id,item.name] for item in baseModels.AdditiveModel.objects.filter(state='1').all()],
            #                      'packaging': [[item.id, item.name] for item in
            #                                   baseModels.PackagingModel.objects.filter(state='1').all()],
            #                      'intermediate': [[item.id, item.name] for item in
            #                                    baseModels.IntermediateModel.objects.filter(state='1').all()],
            #                      'finished': [[item.id, item.name] for item in
            #                                    baseModels.FinishedModel.objects.filter(state='1').all()],
            #                      }
        code = 'base.StoreModel'
        reports = baseModels.ReportFileModel.objects.filter(code=code, type='0', state='1').order_by(
            '-default').all()

        context={'form': form,'pk':pk,'reports':reports,'report_code':code,
                 'report_type': '0', 'material_raws_map':material_raws_map}
        return render(request, self.template_name,context)

    def post(self, request):
        """处理表单提交"""
        _method = request.POST.get('_method')
        _methods = request.POST.get('_methods')
        if _methods=='DELETE':
            delete_ids = request.POST.getlist('delete_ids')  # 隐藏字段传递pk
            return self.delete(request,delete_ids)
        elif 'DELETE' == _method:
            return self.delete(request)

        form = StoreForm(request.POST)
        if form.is_valid():
            try:
                # 提取物料类型并获取对应的模型
                material_type = form.cleaned_data.pop('material_type')
                pk = request.POST.get('pk')  # 隐藏字段传递pk
                model = self.MODEL_MAP.get(material_type)
                raws = form.cleaned_data.pop('raws')
                if not model:
                    # 处理未知物料类型的情况
                    form.add_error('material_type', '无效的物料类型')
                    return render(request, self.template_name, {'form': form})
                # 编辑场景：获取实例；新增场景：无实例
                instance = get_object_or_404(model, pk=pk) if pk else None
                if not instance:

                    # 保存数据到数据库
                    instance = model.objects.create(**form.cleaned_data)
                    getattr(instance, 'raws').set(raws)
                    # 添加成功提示
                    messages.success(request, '物料添加成功！')
                else:
                    # 编辑：更新实例字段
                    for key, value in  form.cleaned_data.items():
                        setattr(instance, key, value)
                    getattr(instance, 'raws').set(raws)
                    instance.save()
                    messages.success(request, "修改成功")
                return redirect(self.success_url)

            except Exception as e:
                # 捕获数据库操作等异常
                messages.error(request, f'添加失败：{str(e)}')
                return render(request, self.template_name, {'form': form})

        # 表单验证失败时返回错误信息
        return render(request, self.template_name, {'form': form})

    def delete(self, request,delete_ids=[]):
        """处理DELETE请求"""
        if not delete_ids:
            material_type = request.POST.get('material_type')
            pk = request.POST.get('pk')  # 隐藏字段传递pk

            # 1. 验证模型类型
            model_class = self.MODEL_MAP.get(material_type)
            if not model_class:
                messages.error(request, "无效的物料类型")
                return redirect(self.success_url)

            # 2. 查询实例（不存在返回404）
            instance = get_object_or_404(model_class, pk=pk)

            # 3. 执行删除
            try:
                instance.raws.clear()
                instance.delete()
                messages.success(request, f"【{instance.name}】已成功删除")
            except Exception as e:
                messages.error(request, f"删除失败：{str(e)}")
        else:
            # 使用事务确保所有操作的原子性
            with transaction.atomic():
                instances=[]
                for delete_id in delete_ids:
                    pk,material_type = delete_id.split('-')
                    # 1. 验证模型类型
                    model_class = self.MODEL_MAP.get(material_type)
                    if not model_class:
                        messages.error(request, "无效的物料类型")
                        return redirect(self.success_url)
                    # 2. 查询实例（不存在返回404）
                    instance = get_object_or_404(model_class, pk=pk)

                    instances.append(instance)
                # 3. 执行删除
                for instance in instances:
                    try:
                        instance.raws.clear()
                        instance.delete()
                    except Exception as e:
                        messages.error(request, f"删除失败：{str(e)}")
                messages.success(request, f"【{len(instances)}条数据】已成功删除")
        # 4. 重定向回列表页
        return redirect(self.success_url)